package com.hilaver.dzmis.service.impl;

import java.util.List;
import java.util.Set;

import com.hilaver.dzmis.Constants;

import com.hilaver.dzmis.codetable.CtMaterialType;
import com.hilaver.dzmis.dao.ProductPackageDAO;
import com.hilaver.dzmis.procurement.ProductPackage;
import com.hilaver.dzmis.procurement.ProductPackageItem;
import com.hilaver.dzmis.product.ProductIdentification;
import com.hilaver.dzmis.product.ProductOrderItem;
import com.hilaver.dzmis.product.ProductYarn;
import com.hilaver.dzmis.service.AbstractBaseService;
import com.hilaver.dzmis.util.SimpleObj2XML;

public class ProductPackageServiceImpl extends AbstractBaseService {

	public static final String COLUMN_PRODUCT_PACKAGE_ID = "productPackage.id";

	public static final String COLUMN_CUSTOMER_NAME = "customerName";

	public static final String COLUMN_CUSTOMER_ID = "customerID";

	private ProductIdentificationServiceImpl piService;

	private CtServiceImpl cs;

	private ProductPackageDAO dao;

	public ProductPackageServiceImpl() {
		this.dao = new ProductPackageDAO();
		this.cs = new CtServiceImpl();
	}

	public ProductPackage getObj(Integer id) throws Exception {
		return (ProductPackage) this.dao
				.get(ProductPackage.class.getName(), id);
	}

	@Override
	public String delete(int id) throws Exception {
		return super.delete(ProductPackage.class.getName(), id);
	}

	@Override
	public String get(int id) throws Exception {
		ProductPackage obj = (ProductPackage) this.dao.get(ProductPackage.class
				.getName(), id);
		StringBuffer xmlSB = new StringBuffer();
		xmlSB.append(Constants.XML_DOC_DEFINE);
		xmlSB.append(Constants.XML_ROOT_TAG[0]);
		xmlSB.append(Constants.XML_ITEM_TAG[0]);
		xmlSB.append(SimpleObj2XML.toXMLFragment(obj));

		xmlSB.append("<" + COLUMN_CUSTOMER_ID + ">");
		xmlSB.append(Constants.XML_CDATA[0]);
		xmlSB.append(obj.getBiFranceCustomer().getId());
		xmlSB.append(Constants.XML_CDATA[1]);
		xmlSB.append("</" + COLUMN_CUSTOMER_ID + ">");

		xmlSB.append("<" + COLUMN_CUSTOMER_NAME + ">");
		xmlSB.append(Constants.XML_CDATA[0]);
		xmlSB.append(obj.getBiFranceCustomer().getName());
		xmlSB.append(Constants.XML_CDATA[1]);
		xmlSB.append("</" + COLUMN_CUSTOMER_NAME + ">");

		xmlSB.append("<" + COLUMN_CUSTOEMR_DEPARTMENT + ">");
		xmlSB.append(Constants.XML_CDATA[0]);
		xmlSB.append(obj.getBiFranceCustomer().getDepartment());
		xmlSB.append(Constants.XML_CDATA[1]);
		xmlSB.append("</" + COLUMN_CUSTOEMR_DEPARTMENT + ">");

		xmlSB.append(Constants.XML_ITEM_TAG[1]);
		xmlSB.append(Constants.XML_ROOT_TAG[1]);
		return xmlSB.toString();
	}

	@Override
	public String getAllPagination(int page, String sort, String order)
			throws Exception {
		return null;
	}

	public String getAllPagination(int page, String sort, String order,
			String[] filters) throws Exception {
		int offset = Constants.PAGE_SIZE * (page - 1);
		List<ProductPackage> objList = this.dao.getAllPagination(
				ProductPackage.class.getName(), offset, Constants.PAGE_SIZE,
				sort, order, filters);
		StringBuffer xmlSB = new StringBuffer();
		xmlSB.append(Constants.XML_DOC_DEFINE);
		xmlSB.append(Constants.XML_ROOT_TAG[0]);
		for (ProductPackage obj : objList) {
			xmlSB.append(Constants.XML_ITEM_TAG[0]);
			xmlSB.append(Constants.XML_INDEX_TAG[0]);
			xmlSB.append(++offset);
			xmlSB.append(Constants.XML_INDEX_TAG[1]);

			xmlSB.append(SimpleObj2XML.toXMLFragment(obj));

			xmlSB.append("<" + COLUMN_CUSTOMER_NAME + ">");
			xmlSB.append(Constants.XML_CDATA[0]);
			xmlSB.append(obj.getBiFranceCustomer().getName());
			xmlSB.append(Constants.XML_CDATA[1]);
			xmlSB.append("</" + COLUMN_CUSTOMER_NAME + ">");

			xmlSB.append("<" + COLUMN_CUSTOEMR_DEPARTMENT + ">");
			xmlSB.append(Constants.XML_CDATA[0]);
			xmlSB.append(obj.getBiFranceCustomer().getDepartment());
			xmlSB.append(Constants.XML_CDATA[1]);
			xmlSB.append("</" + COLUMN_CUSTOEMR_DEPARTMENT + ">");

			xmlSB.append(Constants.XML_ITEM_TAG[1]);
		}

		xmlSB.append(Constants.XML_CURRENT_PAGE_TAG[0]);
		xmlSB.append(page);
		xmlSB.append(Constants.XML_CURRENT_PAGE_TAG[1]);

		xmlSB.append(Constants.XML_ITEM_TOTAL_TAG[0]);
		xmlSB
				.append(this.dao.getCount(ProductPackage.class.getName(),
						filters));
		xmlSB.append(Constants.XML_ITEM_TOTAL_TAG[1]);
		xmlSB.append(Constants.XML_ROOT_TAG[1]);
		return xmlSB.toString();
	}

	public String getAll(Integer piId) throws Exception {

		return null;
	}

	public String editItem(Integer pId, Integer[] ids) throws Exception {
		ProductIdentification pi;
		for (int i = 0; i < ids.length; i++) {
			pi = (ProductIdentification) this.dao.get(
					ProductIdentification.class.getName(), ids[i]);
			if (pi != null) {
				ProductPackage p = new ProductPackage();
				p.setId(pId);
				pi.setProductPackage(p);
				this.dao.saveOrUpdate(pi);
			}
		}
		return "{success: true}";
	}

	public String getItemAll(Integer id) throws Exception {

		this.piService = new ProductIdentificationServiceImpl();
		this.piService.setLocale(this.locale);

		String[] filters = new String[] { COLUMN_PRODUCT_PACKAGE_ID + " = '"
				+ id + "'" };
		List<ProductIdentification> objList = this.dao.getAll(
				ProductIdentification.class.getName(), COLUMN_ID,
				Constants.ORDER_DESC, filters);

		StringBuffer xmlSB = new StringBuffer();
		int offset = 0;
		xmlSB.append(Constants.XML_DOC_DEFINE);
		xmlSB.append(Constants.XML_ROOT_TAG[0]);
		for (ProductIdentification pi : objList) {
			xmlSB.append(Constants.XML_ITEM_TAG[0]);
			xmlSB.append(Constants.XML_INDEX_TAG[0]);
			xmlSB.append(++offset);
			xmlSB.append(Constants.XML_INDEX_TAG[1]);

			xmlSB.append("<" + COLUMN_ID + ">");
			xmlSB.append(pi.getId());
			xmlSB.append("</" + COLUMN_ID + ">");
			xmlSB.append(this.piService.toXMLFragment(pi));

			xmlSB.append(Constants.XML_ITEM_TAG[1]);
		}
		xmlSB.append(Constants.XML_CURRENT_PAGE_TAG[0]);
		xmlSB.append(Constants.XML_CURRENT_PAGE_TAG[1]);
		xmlSB.append(Constants.XML_ITEM_TOTAL_TAG[0]);
		xmlSB.append(this.dao.getCount(ProductIdentification.class.getName(),
				filters));
		xmlSB.append(Constants.XML_ITEM_TOTAL_TAG[1]);
		xmlSB.append(Constants.XML_ROOT_TAG[1]);
		return xmlSB.toString();
	}

	public List<ProductPackageItem> getPackageItemListAll(Integer id)
			throws Exception {
		return this.dao.getProductPackageItemFrom(id);
	}

	public List<ProductPackageItem> getPackageItemListFrom(
			ProductIdentification pi) throws Exception {
		String yarnName = "";
		Set<ProductYarn> pySet = pi.getProductYarns();
		for (ProductYarn py : pySet) {
			yarnName = py.getBiYarn().getReference();
		}
		List<ProductPackageItem> objList = this.dao.getProductPackageItemFrom(
				pi.getProductPackage().getId(), pi.getOrderNumber(), pi
						.getReference(), yarnName);
		return objList;
	}

	public String getPackageItemAll(Integer id) throws Exception {
		List<ProductPackageItem> objList = this.dao
				.getProductPackageItemFrom(id);

		StringBuffer xmlSB = new StringBuffer();
		int offset = 0;
		xmlSB.append(Constants.XML_DOC_DEFINE);
		xmlSB.append(Constants.XML_ROOT_TAG[0]);
		for (ProductPackageItem ppi : objList) {
			xmlSB.append(Constants.XML_ITEM_TAG[0]);
			xmlSB.append(Constants.XML_INDEX_TAG[0]);
			xmlSB.append(++offset);
			xmlSB.append(Constants.XML_INDEX_TAG[1]);

			xmlSB.append(SimpleObj2XML.toXMLFragment(ppi));

			xmlSB.append(Constants.XML_ITEM_TAG[1]);
		}
		xmlSB.append(Constants.XML_CURRENT_PAGE_TAG[0]);
		xmlSB.append(Constants.XML_CURRENT_PAGE_TAG[1]);
		xmlSB.append(Constants.XML_ITEM_TOTAL_TAG[0]);
		xmlSB.append(Constants.XML_ITEM_TOTAL_TAG[1]);
		xmlSB.append(Constants.XML_ROOT_TAG[1]);
		return xmlSB.toString();
	}

	public String editPackageItem(ProductPackageItem ppi) throws Exception {
		return super.edit(ppi);
	}

	public String getPackageItem(Integer id) throws Exception {
		ProductPackageItem obj = (ProductPackageItem) this.dao.get(
				ProductPackageItem.class.getName(), id);
		StringBuffer xmlSB = new StringBuffer();
		xmlSB.append(Constants.XML_DOC_DEFINE);
		xmlSB.append(Constants.XML_ROOT_TAG[0]);
		xmlSB.append(Constants.XML_ITEM_TAG[0]);
		xmlSB.append(SimpleObj2XML.toXMLFragment(obj));
		xmlSB.append(Constants.XML_ITEM_TAG[1]);
		xmlSB.append(Constants.XML_ROOT_TAG[1]);
		return xmlSB.toString();
	}

	public String deletePackageItem(Integer id) throws Exception {
		return super.delete(ProductPackageItem.class.getName(), id);
	}

	public String deleteItem(Integer id) throws Exception {
		ProductIdentification pi = (ProductIdentification) this.dao.get(
				ProductIdentification.class.getName(), id);
		if (pi != null) {
			pi.setProductPackage(null);
			this.dao.saveOrUpdate(pi);
		}
		return "success";
	}

	public String orderPackage(Integer id) throws Exception {
		this.dao.deleteProductPackageItemFrom(id);
		ProductPackage pp = (ProductPackage) this.dao.get(ProductPackage.class
				.getName(), id);
		List<ProductOrderItem> poiList = this.dao.getProductOrderItemFrom(id);
		Integer packageUnit = pp.getUnit();

		ProductPackageItem ppi = null;
		Integer packageNumber = 0;
		String currentOrderNumber = "";
		String currentReference = "";
		String currentColorNumber = "";
		String currentYarnName = "";
		String orderNumber;
		String reference;
		String colorNumber;
		String yarnName;
		Integer reaminSpace;
		for (int i = 0; i < poiList.size(); i++) {
			orderNumber = poiList.get(i).getProductIdentification()
					.getOrderNumber();
			reference = poiList.get(i).getProductIdentification()
					.getReference();
			colorNumber = poiList.get(i).getColorNumber();
			yarnName = "";
			Set<ProductYarn> pySet = poiList.get(i).getProductIdentification()
					.getProductYarns();
			for (ProductYarn py : pySet) {
				yarnName = py.getBiYarn().getReference();
			}

			if (i == 0) { // Get Product package item at first
				currentOrderNumber = orderNumber;
				currentReference = reference;
				currentColorNumber = colorNumber;
				currentYarnName = yarnName;
			}

			if (!currentOrderNumber.equals(orderNumber)) {
				packageNumber = 0;
				this.storePackage(ppi);
				ppi = this.getNewPackage(orderNumber, reference, colorNumber,
						yarnName, ++packageNumber, id);
				currentOrderNumber = orderNumber;
				currentReference = reference;
				currentColorNumber = colorNumber;
				currentYarnName = yarnName;
			} else {
				ppi = this.getNewPackage(orderNumber, reference, colorNumber,
						yarnName, ++packageNumber, id);
			}

			Integer remainS = poiList.get(i).getAmountS();
			while (remainS > this.getReaminSpace(ppi)) {
				reaminSpace = this.getReaminSpace(ppi);
				this.fillPackage(ppi, "S", remainS);
				remainS -= reaminSpace;
				this.storePackage(ppi);
				ppi = this.getNewPackage(orderNumber, reference, colorNumber,
						yarnName, ++packageNumber, id);
			}
			if (remainS != 0) {
				this.fillPackage(ppi, "S", remainS);
			}

			Integer remainM = poiList.get(i).getAmountM();
			while (remainM > this.getReaminSpace(ppi)) {
				reaminSpace = this.getReaminSpace(ppi);
				this.fillPackage(ppi, "M", remainM);
				remainM -= reaminSpace;
				this.storePackage(ppi);
				ppi = this.getNewPackage(orderNumber, reference, colorNumber,
						yarnName, ++packageNumber, id);
			}
			if (remainM != 0) {
				this.fillPackage(ppi, "M", remainM);
			}

			Integer remainL = poiList.get(i).getAmountL();
			while (remainL > this.getReaminSpace(ppi)) {
				reaminSpace = this.getReaminSpace(ppi);
				this.fillPackage(ppi, "L", remainL);
				remainL -= reaminSpace;
				this.storePackage(ppi);
				ppi = this.getNewPackage(orderNumber, reference, colorNumber,
						yarnName, ++packageNumber, id);
			}
			if (remainL != 0) {
				this.fillPackage(ppi, "L", remainL);
			}

			Integer remainXl = poiList.get(i).getAmountXl();
			while (remainXl > this.getReaminSpace(ppi)) {
				reaminSpace = this.getReaminSpace(ppi);
				this.fillPackage(ppi, "Xl", remainXl);
				remainXl -= reaminSpace;
				this.storePackage(ppi);
				ppi = this.getNewPackage(orderNumber, reference, colorNumber,
						yarnName, ++packageNumber, id);
			}
			if (remainXl != 0) {
				this.fillPackage(ppi, "Xl", remainXl);
			}

			Integer remainXxl = poiList.get(i).getAmountXxl();
			while (remainXxl > this.getReaminSpace(ppi)) {
				reaminSpace = this.getReaminSpace(ppi);
				this.fillPackage(ppi, "Xxl", remainXxl);
				remainXxl -= reaminSpace;
				this.storePackage(ppi);
				ppi = this.getNewPackage(orderNumber, reference, colorNumber,
						yarnName, ++packageNumber, id);
			}
			if (remainXxl != 0) {
				this.fillPackage(ppi, "Xxl", remainXxl);
			}

			Integer remainXxxl = poiList.get(i).getAmountXxxl();
			while (remainXxxl > this.getReaminSpace(ppi)) {
				reaminSpace = this.getReaminSpace(ppi);
				this.fillPackage(ppi, "Xxxl", remainXxxl);
				remainXxxl -= reaminSpace;
				this.storePackage(ppi);
				ppi = this.getNewPackage(orderNumber, reference, colorNumber,
						yarnName, ++packageNumber, id);
			}
			if (remainXxxl != 0) {
				this.fillPackage(ppi, "Xxxl", remainXxxl);
			}

			this.storePackage(ppi);
		}

		this.mergeProductPackageItem(id);
		return "success";
	}

	private void mergeProductPackageItem(Integer id) throws Exception {
		ProductPackage pp = (ProductPackage) this.dao.get(ProductPackage.class
				.getName(), id);
		List<ProductPackageItem> ppiList = this.dao
				.getProductPackageItemFrom(id);

		Integer packageUnit = pp.getUnit();

		Integer mergeTimes;
		Integer usedSpace;
		for (int i = 0; i < ppiList.size(); i++) {
			mergeTimes = 0;
			usedSpace = 0;
			usedSpace = ppiList.get(i).getPackageAmount();

			if (usedSpace < packageUnit) {
				for (int j = i + 1; j < ppiList.size(); j++) {
					usedSpace += ppiList.get(j).getPackageAmount();
					if (usedSpace <= packageUnit
							&& ppiList.get(i).getOrderNumber().equals(
									ppiList.get(j).getOrderNumber())) {
						ppiList.get(j).setPackageNumber(
								ppiList.get(i).getPackageNumber());
						mergeTimes++;
						this.storePackage(ppiList.get(j));
					}
				}
			}
			if (mergeTimes > 0) {
				for (int j = i + mergeTimes + 1; j < ppiList.size(); j++) {
					if (ppiList.get(i).getOrderNumber().equals(
							ppiList.get(j).getOrderNumber())) {
						ppiList.get(j).setPackageNumber(
								ppiList.get(j).getPackageNumber() - mergeTimes);
						this.storePackage(ppiList.get(j));
					}
				}
			}

			i = i + mergeTimes;
		}

	}

	private ProductPackageItem getNewPackage(String orderNumber,
			String reference, String colorNumber, String yarnName,
			Integer packageNumber, Integer parentId) throws Exception {
		ProductPackageItem ppi = new ProductPackageItem();
		ppi.setOrderNumber(orderNumber);
		ppi.setReference(reference);
		ppi.setColor(colorNumber);
		ppi.setPackageNumber(packageNumber);
		ppi.setYarnName(yarnName);
		ppi.setPackageAmount(0);
		ppi.setChoice("1");
		ppi.setStandard("N");
		ProductPackage pp = (ProductPackage) this.dao.get(ProductPackage.class
				.getName(), parentId);
		ppi.setProductPackage(pp);
		return ppi;
	}

	private Integer getReaminSpace(ProductPackageItem ppi) throws Exception {
		if (ppi == null) {
			throw new Exception();
		}
		Integer packageUnit = ppi.getProductPackage().getUnit();
		Integer usedSpace = ppi.getPackageAmount();
		if (usedSpace == null) {
			usedSpace = 0;
		}
		return packageUnit - usedSpace;
	}

	private boolean isPackageFull(ProductPackageItem ppi, Integer amount) {
		Integer packageUnit = ppi.getProductPackage().getUnit();
		Integer usedSpace = ppi.getPackageAmount();
		if (usedSpace == null) {
			usedSpace = 0;
		}
		if ((usedSpace + amount) > packageUnit) {
			return true;
		}
		return false;
	}

	private Integer fillPackage(ProductPackageItem ppi, String size,
			Integer amount) {
		if (amount == null) {
			return -1;
		}
		Integer packageUnit = ppi.getProductPackage().getUnit();
		Integer usedSpace = ppi.getPackageAmount();
		Integer remainSpace = packageUnit - usedSpace;

		if (remainSpace > amount) {
			if (size.equals("S")) {
				ppi.setAmountS(amount);
			} else if (size.equals("M")) {
				ppi.setAmountM(amount);
			} else if (size.equals("L")) {
				ppi.setAmountL(amount);
			} else if (size.equals("Xl")) {
				ppi.setAmountXl(amount);
			} else if (size.equals("Xxl")) {
				ppi.setAmountXxl(amount);
			} else if (size.equals("Xxxl")) {
				ppi.setAmountXxxl(amount);
			}
			ppi.setPackageAmount(usedSpace + amount);
		} else {
			if (size.equals("S")) {
				ppi.setAmountS(remainSpace);
			} else if (size.equals("M")) {
				ppi.setAmountM(remainSpace);
			} else if (size.equals("L")) {
				ppi.setAmountL(remainSpace);
			} else if (size.equals("Xl")) {
				ppi.setAmountXl(remainSpace);
			} else if (size.equals("Xxl")) {
				ppi.setAmountXxl(remainSpace);
			} else if (size.equals("Xxxl")) {
				ppi.setAmountXxxl(remainSpace);
			}
			ppi.setPackageAmount(packageUnit);
		}

		return amount - remainSpace;
	}

	private void storePackage(ProductPackageItem ppi) throws Exception {
		Integer total = 0;
		if (ppi.getAmountS() != null) {
			total += ppi.getAmountS();
		}
		if (ppi.getAmountM() != null) {
			total += ppi.getAmountM();
		}
		if (ppi.getAmountL() != null) {
			total += ppi.getAmountL();
		}
		if (ppi.getAmountXl() != null) {
			total += ppi.getAmountXl();
		}
		if (ppi.getAmountXxl() != null) {
			total += ppi.getAmountXxl();
		}
		if (ppi.getAmountXxxl() != null) {
			total += ppi.getAmountXxxl();
		}
		ppi.setPackageAmount(total);
		this.dao.saveOrUpdate(ppi);
	}

	public static void main(String[] args) {
		ProductPackageServiceImpl pps = new ProductPackageServiceImpl();
		try {
			System.out.println(pps.getItemAll(3));
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

}
